//-----------------------------------------------------------------------------
//  Copyright (C) 2005-2008 Thomas S. Ullrich 
//
//  This file is part of the Solitaire Mahjong project.
//
//  This file may be used under the terms of the GNU General Public License.
//  This project is free software; you can redistribute it and/or modify it
//  under the terms of the GNU General Public License.
//  
//  Author: Thomas S. Ullrich
//  Last update: June 1, 2007
//-----------------------------------------------------------------------------
#include <algorithm>
#include <QMessageBox>
#include <QSettings>
#include <QHeaderView>
#include <QtDebug>
#include "smSettings.h"
#include "smHighscoreList.h"
#include "smDefinitions.h"

smHighscoreList::smHighscoreList(QWidget* parent, Qt::WindowFlags fl) : QDialog(parent, fl)
{
    ui.setupUi(this);
    
    ui.mTableWidget->setSortingEnabled(false); // no sorting do it manually
    //setModal(true);
    //  connect(ui.buttonClear, SIGNAL(released()), this, SLOT(clear())); already done in 'ui'

    QHeaderView* hHeader = ui.mTableWidget->horizontalHeader();

    hHeader->setResizeMode(QHeaderView::Fixed);
    hHeader->setResizeMode(1, QHeaderView::Stretch);
    ui.mTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
    ui.mTableWidget->verticalHeader()->hide();
    
    ui.mTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
    move(smSettings::instance()->mHighscoreWindowPosition);
}

smHighscoreList::~smHighscoreList()
{ /* noop */ }

bool smHighscoreList::insertEntry(smHighscoreEntry& entry)
{
    if (!entry.isValid()) return false;
    
    mLastEntry = entry;
    smHighscoreEntryCompare cmp;
    
    if (mList.size() < smMaxHighscoreEntries) {   // highscore list not full, always add new
        mList.push_back(entry);
        sort(mList.begin(), mList.end(), smHighscoreEntryCompare());
        return true;
    }
    else {
        if (cmp(entry, mList[smMaxHighscoreEntries-1])) {
            mList[smMaxHighscoreEntries-1] = entry;  // supercedes existing entry, replace last
            sort(mList.begin(), mList.end(), smHighscoreEntryCompare());
            return true;
        }
    }
    return false;
}

void smHighscoreList::print(ostream& os)
{
    vector<smHighscoreEntry>::iterator iter;
    for (iter = mList.begin(); iter != mList.end(); iter++)
        os << *iter << endl;
}

void smHighscoreList::sync()
{
    ui.mTableWidget->clearContents();
    QString rank;
    for (unsigned int i=0; i<mList.size(); i++) {
        rank.setNum(i+1);
        ui.mTableWidget->setItem(i, 0, new QTableWidgetItem(rank));
        ui.mTableWidget->item(i, 0)->setTextAlignment(Qt::AlignHCenter); 
        ui.mTableWidget->setItem(i, 1, new QTableWidgetItem(mList[i].date()));
        ui.mTableWidget->item(i, 1)->setTextAlignment(Qt::AlignHCenter); 
        ui.mTableWidget->setItem(i, 2, new QTableWidgetItem(mList[i].tiles()));
        ui.mTableWidget->item(i, 2)->setTextAlignment(Qt::AlignHCenter); 
        ui.mTableWidget->setItem(i, 3, new QTableWidgetItem(mList[i].hints()));
        ui.mTableWidget->item(i, 3)->setTextAlignment(Qt::AlignHCenter); 
        ui.mTableWidget->setItem(i, 4, new QTableWidgetItem(mList[i].undos()));
        ui.mTableWidget->item(i, 4)->setTextAlignment(Qt::AlignHCenter); 
        ui.mTableWidget->setItem(i, 5, new QTableWidgetItem(mList[i].duration()));
        ui.mTableWidget->item(i, 5)->setTextAlignment(Qt::AlignHCenter); 
    }
    update();
    
    //
    //  Mark last item
    //
    if (mLastEntry.isValid()) {
        QList<QTableWidgetItem*> list = ui.mTableWidget->findItems(mLastEntry.date(), Qt::MatchExactly);
        if (!list.empty()) {
            int row = ui.mTableWidget->row(list[0]);
            for (int col=0; col<ui.mTableWidget->columnCount(); col++) {
                ui.mTableWidget->item(row, col)->setForeground(Qt::red);
            }
        }
    }
}

void smHighscoreList::syncAndShow()
{
    sync();
    show();
}

void smHighscoreList::clear()
{
    int ret =  QMessageBox::question(this, "Solitaire Mahjong", 
                                     "Are you sure you want to delete all high scrore entries?", 
                                     QMessageBox::Ok | QMessageBox::Cancel,
                                     QMessageBox::Cancel);
    if (ret != QMessageBox::Ok) return;
    mList.clear();
    mLastEntry = smHighscoreEntry();
    sync();
    update();
}

void smHighscoreList::load(QSettings *s)
{
    char text[64];
    unsigned int n = s->value("/StoredHighScores", 0).toUInt();
    unsigned int csRead = s->value("/Checksum", 0).toUInt();
    if (n > smMaxHighscoreEntries) n = smMaxHighscoreEntries; // happens when max got changed
    for (unsigned int i=0; i<n; i++) {
        sprintf(text,"/%d", i);
        s->beginGroup(text);
        time_t ts = s->value("/StartTime", 0).toUInt();
        time_t te = s->value("/EndTime", 0).toUInt();
        int nt = s->value("/TilesLeft", 0).toUInt();
        int nh = s->value("/HintsUsed", 0).toUInt();
        int nu = s->value("/UndosUsed", 0).toUInt();
        s->endGroup();
        smHighscoreEntry entry(ts, te, nt, nh, nu);
        if (entry.isValid()) mList.push_back(entry);
    }
    sort(mList.begin(), mList.end(), smHighscoreEntryCompare());
    unsigned int csActual = checksum();
    if (mList.size() && csActual != csRead) {  // high score either corrupt or someone cheated
        QMessageBox::warning( 0, "Solitaire Mahjong",
                        "The high score history is corrupt (checksum mismatch).\n"
                        "Either the file resource file got corrupted or someone\n"
                        "tampered with the file.\n"
                        "For safety reasons the current high score list is reset.");
        clear();
    }
}

void smHighscoreList::save(QSettings *s)
{
    char text[64];
    s->setValue("/StoredHighScores", static_cast<unsigned int>(mList.size()));
    s->setValue("/Checksum", checksum());
    for (unsigned int i=0; i<mList.size(); i++) {
        sprintf(text,"/%d", i);
        s->beginGroup(text);
        s->setValue("/StartTime", static_cast<unsigned int>(mList[i].startTime()));
        s->setValue("/EndTime",   static_cast<unsigned int>(mList[i].endTime()));
        s->setValue("/TilesLeft", mList[i].tilesLeft());
        s->setValue("/HintsUsed", mList[i].hintsUsed());
        s->setValue("/UndosUsed", mList[i].undosUsed());
        s->endGroup();
    }
}

unsigned int smHighscoreList::checksum() const
{
    QByteArray a;
    QDataStream stream(&a, QIODevice::ReadWrite);       // open on a's data
    for (unsigned int i=0; i<mList.size(); i++) {
        stream << static_cast<unsigned int>(mList[i].startTime()) << static_cast<unsigned int>(mList[i].endTime())
               << mList[i].tilesLeft() << mList[i].hintsUsed()
               << mList[i].undosUsed();
    }
    return qChecksum (a.data(), a.size());
}

void smHighscoreList::hideEvent(QHideEvent*)
{
    smSettings::instance()->mHighscoreWindowPosition = pos(); 
}


void smHighscoreList::showEvent(QShowEvent*)
{
    move(smSettings::instance()->mHighscoreWindowPosition);
}
